/**
 * Copyright (c) 2015 - present LibDriver All rights reserved
 *
 * The MIT License (MIT)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * @file      wire.c
 * @brief     单线总线源文件
 * @version   1.0.0
 * @author    Shifeng Li
 * @date      2022-11-11
 *
 * <h3>history</h3>
 * <table>
 * <tr><th>Date        <th>Version  <th>Author      <th>Description
 * <tr><td>2022/11/11  <td>1.0      <td>Shifeng Li  <td>first upload
 * </table>
 */

#include "wire.h"

/**
 * @brief 位操作定义
 */
#define BITBAND(addr, bitnum) ((addr & 0xF0000000) + 0x2000000 + ((addr & 0xFFFFF) << 5) + (bitnum << 2))
#define MEM_ADDR(addr) *((volatile uint32_t *)(addr))
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))

/**
 * @brief 单线GPIO操作定义
 */
#define GPIOA_ODR_Addr (GPIOA_BASE + 0x0C)   /**< GPIOA输出数据寄存器地址 */
#define GPIOA_IDR_Addr (GPIOA_BASE + 0x08)   /**< GPIOA输入数据寄存器地址 */
#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr, n) /**< GPIOA输出位操作 */
#define PAin(n) BIT_ADDR(GPIOA_IDR_Addr, n)  /**< GPIOA输入数据寄存器地址 */
#define IO_IN()                          \
    {                                    \
        GPIOA->CRH &= ~(0xF << (0 * 4)); \
        GPIOA->CRH |= 0x8 << (0 * 4);    \
    } /**< 配置为输入模式 */
#define IO_OUT()                         \
    {                                    \
        GPIOA->CRH &= ~(0xF << (0 * 4)); \
        GPIOA->CRH |= 0x3 << (0 * 4);    \
    }                   /**< 配置为输出模式 */
#define DQ_OUT PAout(8) /**< 数据线输出 */
#define DQ_IN PAin(8)   /**< 数据线输入 */

/**
 * @brief  单线总线初始化
 * @return 状态码
 *         - 0 成功
 * @note   IO引脚为PA8
 */
uint8_t wire_init(void)
{
    GPIO_InitTypeDef GPIO_Initure;

    /* 使能GPIO时钟 */
    __HAL_RCC_GPIOA_CLK_ENABLE();

    /* GPIO初始化 */
    GPIO_Initure.Pin = GPIO_PIN_8;
    GPIO_Initure.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_Initure.Pull = GPIO_PULLUP;
    GPIO_Initure.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_Initure);

    /* 输出模式 */
    IO_OUT();

    /* 设置高电平 */
    DQ_OUT = 1;

    /* 输入模式 */
    IO_IN();

    return 0;
}

/**
 * @brief  单线总线反初始化
 * @return 状态码
 *         - 0 成功
 * @note   无
 */
uint8_t wire_deinit(void)
{
    /* GPIO反初始化 */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_8);

    return 0;
}

/**
 * @brief      单线总线读取数据
 * @param[out] *value 读取数据缓冲区指针
 * @return     状态码
 *             - 0 成功
 * @note       无
 */
uint8_t wire_read(uint8_t *value)
{
    /* 输入模式 */
    IO_IN();

    /* 读取数据 */
    *value = DQ_IN;

    return 0;
}

/**
 * @brief     单线总线写入数据
 * @param[in] value 写入数据
 * @return    状态码
 *            - 0 成功
 * @note      无
 */
uint8_t wire_write(uint8_t value)
{
    /* 输出模式 */
    IO_OUT();

    /* 设置数据 */
    DQ_OUT = value;

    return 0;
}

/**
 * @brief  单线时钟总线初始化
 * @return 状态码
 *         - 0 成功
 * @note   IO引脚为PA0
 */
uint8_t wire_clock_init(void)
{
    GPIO_InitTypeDef GPIO_Initure;

    /* 使能GPIO时钟 */
    __HAL_RCC_GPIOA_CLK_ENABLE();

    /* GPIO初始化 */
    GPIO_Initure.Pin = GPIO_PIN_0;
    GPIO_Initure.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_Initure.Pull = GPIO_PULLUP;
    GPIO_Initure.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_Initure);

    return 0;
}

/**
 * @brief  单线时钟总线反初始化
 * @return 状态码
 *         - 0 成功
 * @note   无
 */
uint8_t wire_clock_deinit(void)
{
    /* GPIO反初始化 */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_0);

    return 0;
}

/**
 * @brief     单线时钟总线写入数据
 * @param[in] value 写入数据
 * @return    状态码
 *            - 0 成功
 * @note      无
 */
uint8_t wire_clock_write(uint8_t value)
{
    if (value != 0)
    {
        /* 设置高电平 */
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);
    }
    else
    {
        /* 设置低电平 */
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);
    }

    return 0;
}
